<template>
  <div id="geojson-clip-map" style="width: 100%; height: 100%;"></div>
  <div style="position: absolute; top: 10px; left: 10px; z-index: 100;">
    <button @click="switchGeojson('/area.json')" style="margin-right: 10px; padding: 8px 15px; border: none; border-radius: 5px; background-color: #4CAF50; color: white; cursor: pointer;">
      加载 area.json
    </button>
    <button @click="switchGeojson('/area1.json')" style="padding: 8px 15px; border: none; border-radius: 5px; background-color: #008CBA; color: white; cursor: pointer;">
      加载 area1.json
    </button>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import { XYZ } from 'ol/source';
import { defaults as DefaultControls } from 'ol/control';
import { fromLonLat } from 'ol/proj';
import RenderEvent from 'ol/render/Event';
import { unByKey } from 'ol/Observable';
import type { EventsKey } from 'ol/events';
import GeoJSON from 'ol/format/GeoJSON';
import Feature from 'ol/Feature';
import Polygon from 'ol/geom/Polygon';
import { extend as extentExtend } from 'ol/extent';

let map: Map | null = null;
let baseLayer: TileLayer | null = null;
let prerenderListenerKey: EventsKey | null = null;
let postrenderListenerKey: EventsKey | null = null;
const geojsonFeature = ref<Feature<Polygon> | null>(null); // 用于存储从 GeoJSON 加载的多边形要素
let view: View | null = null; // 添加 view 变量以便在组件中访问

// 新增：当前加载的 GeoJSON 文件路径
const currentGeojsonFile = ref<string>('/area.json');

// 新增：加载 GeoJSON 并调整视图的函数
const loadGeojsonAndFitView = async (geojsonPath: string) => {
  let initialViewExtent: number[] | undefined;
  geojsonFeature.value = null; // 清空旧的 GeoJSON 要素

  try {
    const response = await fetch(geojsonPath);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    const features = new GeoJSON().readFeatures(data, {
      featureProjection: 'EPSG:3857',
    });
    if (features.length > 0 && features[0].getGeometry() instanceof Polygon) {
      geojsonFeature.value = features[0] as Feature<Polygon>;
      const featureExtent = geojsonFeature.value.getGeometry()!.getExtent();
      const buffer = 100000;
      initialViewExtent = extentExtend(featureExtent, [
        featureExtent[0] - buffer,
        featureExtent[1] - buffer,
        featureExtent[2] + buffer,
        featureExtent[3] + buffer,
      ]);

      console.log('GeoJSON feature extent:', featureExtent);
      console.log('Buffered extent (initialViewExtent):', initialViewExtent);
    }
  } catch (error) {
    console.error(`加载 GeoJSON 文件失败 (${geojsonPath}):`, error);
    initialViewExtent = undefined;
  }

  // 如果地图已经初始化，则更新视图
  if (map && initialViewExtent) {
    // 创建新的视图，设置限制范围
    const newView = new View({
      center: [
        (initialViewExtent[0] + initialViewExtent[2]) / 2,
        (initialViewExtent[1] + initialViewExtent[3]) / 2,
      ],
      zoom: 5,
      projection: 'EPSG:3857',
      rotation: 0,
      minZoom: 1,
      maxZoom: 18,
      extent: initialViewExtent, // 设置视图的限制范围
    });

    // 更新地图的视图
    map.setView(newView);
    view = newView;

    // 调整视图以适应范围
    newView.fit(initialViewExtent, {
      size: map.getSize(),
      padding: [50, 50, 50, 50],
      constrainResolution: true,
      duration: 1000,
    });
  } else if (map && !initialViewExtent) {
    // 如果加载失败且地图已存在，可以考虑重置视图或保持当前视图
    console.warn('GeoJSON 加载失败，未调整地图视图。');
  }
};

onMounted(async () => {
  // 定义底图图层，使用高德地图的业务图服务
  baseLayer = new TileLayer({
    source: new XYZ({
      url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}',
    }),
  });

  // 初始化地图视图（初始时可以给一个默认的中心和缩放，后续会被 GeoJSON 调整）
  view = new View({
    center: fromLonLat([114.30, 30.50]),
    zoom: 5,
    projection: 'EPSG:3857',
    rotation: 0,
    minZoom: 1,
    maxZoom: 18,
  });

  // 初始化地图
  map = new Map({
    controls: DefaultControls().extend([]),
    target: 'geojson-clip-map',
    layers: [baseLayer],
    view: view,
  });

  // 初始加载第一个 GeoJSON 文件
  await loadGeojsonAndFitView(currentGeojsonFile.value);

  // 为底图图层添加 prerender 事件监听器
  prerenderListenerKey = baseLayer.on('prerender', (event) => {
    const context = (event as RenderEvent).context as CanvasRenderingContext2D;

    // 只有当 geojsonFeature.value 存在且地图实例存在时才进行裁剪
    if (geojsonFeature.value && map) {
      context.save();
      context.beginPath();

      const geometry = geojsonFeature.value.getGeometry();
      if (geometry instanceof Polygon) {
        const coordinates = geometry.getCoordinates()[0];
        if (coordinates && coordinates.length > 0) {
          const firstPixel = map.getPixelFromCoordinate(coordinates[0]);
          if (firstPixel) {
            context.moveTo(firstPixel[0], firstPixel[1]);
            for (let i = 1; i < coordinates.length; i++) {
              const pixel = map.getPixelFromCoordinate(coordinates[i]);
              if (pixel) {
                context.lineTo(pixel[0], pixel[1]);
              }
            }
            context.closePath();
            context.clip();
          }
        }
      }
    }
  });

  // 为底图图层添加 postrender 事件监听器
  postrenderListenerKey = baseLayer.on('postrender', (event) => {
    const context = (event as RenderEvent).context as CanvasRenderingContext2D;
    // 只有当之前进行了裁剪（即 geojsonFeature.value 存在）才需要恢复状态
    if (geojsonFeature.value) {
      context.restore();
    }
  });

  console.log("GeojsonClipMap mounted.");
});

// 新增：切换 GeoJSON 文件的函数
const switchGeojson = async (path: string) => {
  currentGeojsonFile.value = path;
  await loadGeojsonAndFitView(path);
};

// 监听 currentGeojsonFile 变化，重新加载 GeoJSON
watch(currentGeojsonFile, (newPath) => {
  // 当 currentGeojsonFile 变化时，loadGeojsonAndFitView 会自动被调用
  // 这里的 watch 主要是为了调试或确保逻辑清晰，实际功能已在 switchGeojson 中实现
  console.log('切换到 GeoJSON 文件:', newPath);
});

onUnmounted(() => {
  if (map) {
    map.setTarget(undefined);
    map = null;
  }
  if (baseLayer) {
    if (prerenderListenerKey) {
      unByKey(prerenderListenerKey);
    }
    if (postrenderListenerKey) {
      unByKey(postrenderListenerKey);
    }
    baseLayer = null;
  }
  geojsonFeature.value = null;
  console.log("GeojsonClipMap unmounted.");
});
</script>

<style scoped>
#geojson-clip-map {
  width: 100%;
  height: 100%;
}
</style> 